(include 'sys/load/class.inc)

(def-class 'host)
(dec-method 'sdl_set_main_ready nil 'virtual (abi-args 0) '(r0))
(dec-method 'sdl_init nil 'virtual (abi-args 1) '(r0))
(dec-method 'sdl_get_error nil 'virtual (abi-args 0) '(r0))
(dec-method 'sdl_quit nil 'virtual (abi-args 0) '(r0))
(dec-method 'sdl_create_window nil 'virtual (abi-args 6) '(r0))
(dec-method 'sdl_create_window_and_renderer nil 'virtual (abi-args 5) '(r0))
(dec-method 'sdl_destroy_window nil 'virtual (abi-args 1) '(r0))
(dec-method 'sdl_delay nil 'virtual (abi-args 1) '(r0))
(dec-method 'sdl_create_renderer nil 'virtual (abi-args 3) '(r0))
(dec-method 'sdl_set_render_draw_color nil 'virtual (abi-args 5) '(r0))
(dec-method 'sdl_render_fill_rect nil 'virtual (abi-args 2) '(r0))
(dec-method 'sdl_render_present nil 'virtual (abi-args 1) '(r0))
(dec-method 'sdl_render_set_clip_rect nil 'virtual (abi-args 2) '(r0))
(dec-method 'sdl_set_render_draw_blend_mode nil 'virtual (abi-args 2) '(r0))
(dec-method 'sdl_poll_event nil 'virtual (abi-args 1) '(r0))
(dec-method 'sdl_render_draw_rect nil 'virtual (abi-args 2) '(r0))
(dec-method 'sdl_free_surface nil 'virtual (abi-args 1) '(r0))
(dec-method 'sdl_create_texture_from_surface nil 'virtual (abi-args 2) '(r0))
(dec-method 'sdl_destroy_texture nil 'virtual (abi-args 1) '(r0))
(dec-method 'sdl_render_copy nil 'virtual (abi-args 4) '(r0))
(dec-method 'sdl_set_texture_blend_mode nil 'virtual (abi-args 2) '(r0))
(dec-method 'sdl_set_texture_color_mod nil 'virtual (abi-args 4) '(r0))
(dec-method 'sdl_create_rgb_surface_from nil 'virtual (abi-args 9) '(r0))
(dec-method 'sdl_compose_custom_blend_mode nil 'virtual (abi-args 6) '(r0))
(dec-method 'sdl_create_texture nil 'virtual (abi-args 5) '(r0))
(dec-method 'sdl_set_render_target nil 'virtual (abi-args 2) '(r0))
(dec-method 'sdl_render_clear nil 'virtual (abi-args 1) '(r0))

(dec-method 'exit nil 'virtual (abi-args 1))
(dec-method 'stat nil 'virtual (abi-args 2) '(r0))
(dec-method 'open nil 'virtual (abi-args 2) '(r0))
(dec-method 'close nil 'virtual (abi-args 1) '(r0))
(dec-method 'unlink nil 'virtual (abi-args 1) '(r0))
(dec-method 'read nil 'virtual (abi-args 3) '(r0))
(dec-method 'write nil 'virtual (abi-args 3) '(r0))
(dec-method 'mmap nil 'virtual (abi-args 3) '(r0))
(dec-method 'munmap nil 'virtual (abi-args 3) '(r0))
(dec-method 'mprotect nil 'virtual (abi-args 3) '(r0))
(dec-method 'gettime nil 'virtual '() '(r0))
(dec-method 'open_shared nil 'virtual (abi-args 2) '(r0))
(dec-method 'close_shared nil 'virtual (abi-args 2) '(r0))
(dec-method 'clear_icache nil 'virtual (abi-args 2) '(r0))

(defcfun host-call-table (_1 _2 _5 &optional _3 _4 _6)
	;_1 = class name
	;_2 = member name
	;_5 = host function table
	;_3 = in parameters
	;_4 = out parameters
	;_6 = temp reg
	(setd _6 r13)
	(defq m (method-lookup _1 _2) x (list) s (elem 2 m))
	(if (eql (elem 1 m) 'static)
		(throw "Abi methods must be virtual !" (list _1 _2)))
	(if (or (find _5 s) (find _6 s))
		(throw "Dispatch/Temp register conflicts with arg !" (list _5 _6 s)))
	(assign _3 s)
	(when (> (defq ls (length s)) (defq la (length (abi-args))))
		(setq x (reduce-rev (lambda (x y) (push x y)) (slice la ls s) (list))))
	(vp-call-abi _6 _5 (- (elem 4 m) ptr_size) x)
	(if _4 (assign (elem 3 m) _4)))

(defcfun host-call (_1 _2 &optional _3 _4 _5 _6)
	;_1 = class name
	;_2 = member name
	;_3 = in parameters
	;_4 = out parameters
	;_5 = dispatch reg
	;_6 = temp reg
	(setd _5 r14 _6 r13)
	(f-bind 'sys_load 'statics _5)
	(vp-cpy-ir _5 ld_statics_host_funcs _5)
	(host-call-table _1 _2 _5 _3 _4 _6))

;;;;;;;;;;;;;;;
; SDL interface
;;;;;;;;;;;;;;;

(defcvar 'SDL_INIT_TIMER 0x00000001)
(defcvar 'SDL_INIT_AUDIO 0x00000010)
(defcvar 'SDL_INIT_VIDEO 0x00000020)
(defcvar 'SDL_INIT_JOYSTICK 0x00000200)
(defcvar 'SDL_INIT_HAPTIC 0x00001000)
(defcvar 'SDL_INIT_GAMECONTROLLER 0x00002000)
(defcvar 'SDL_INIT_EVENTS 0x00004000)
(defcvar 'SDL_INIT_NOPARACHUTE 0x00100000)
(defcvar 'SDL_INIT_EVERYTHING (logior SDL_INIT_TIMER SDL_INIT_AUDIO SDL_INIT_VIDEO SDL_INIT_EVENTS SDL_INIT_JOYSTICK SDL_INIT_HAPTIC SDL_INIT_GAMECONTROLLER))

(defcvar 'SDL_WINDOW_FULLSCREEN 0x00000001)
(defcvar 'SDL_WINDOW_OPENGL 0x00000002)
(defcvar 'SDL_WINDOW_SHOWN 0x00000004)
(defcvar 'SDL_WINDOW_HIDDEN 0x00000008)
(defcvar 'SDL_WINDOW_BORDERLESS 0x00000010)
(defcvar 'SDL_WINDOW_RESIZABLE 0x00000020)
(defcvar 'SDL_WINDOW_MINIMIZED 0x00000040)
(defcvar 'SDL_WINDOW_MAXIMIZED 0x00000080)
(defcvar 'SDL_WINDOW_INPUT_GRABBED 0x00000100)
(defcvar 'SDL_WINDOW_INPUT_FOCUS 0x00000200)
(defcvar 'SDL_WINDOW_MOUSE_FOCUS 0x00000400)
(defcvar 'SDL_WINDOW_FULLSCREEN_DESKTOP (logior SDL_WINDOW_FULLSCREEN 0x00001000))
(defcvar 'SDL_WINDOW_FOREIGN 0x00000800)
(defcvar 'SDL_WINDOW_ALLOW_HIGHDPI 0x00002000)

(defcvar 'SDL_WINDOWPOS_UNDEFINED_MASK 0x1FFF0000)
(defcvar 'SDL_WINDOWPOS_UNDEFINED SDL_WINDOWPOS_UNDEFINED_MASK)
(defcvar 'SDL_WINDOWPOS_CENTERED_MASK 0x2FFF0000)

(defcvar 'SDL_RENDERER_SOFTWARE 0x00000001)
(defcvar 'SDL_RENDERER_ACCELERATED 0x00000002)
(defcvar 'SDL_RENDERER_PRESENTVSYNC 0x00000004)
(defcvar 'SDL_RENDERER_TARGETTEXTURE 0x00000008)

(defcvar 'SDL_BLENDMODE_NONE 0)
(defcvar 'SDL_BLENDMODE_BLEND 1)
(defcvar 'SDL_BLENDMODE_ADD 2)
(defcvar 'SDL_BLENDMODE_MOD 4)

(defcvar 'SDL_BLENDOPERATION_ADD 0x1)
(defcvar 'SDL_BLENDOPERATION_SUBTRACT 0x2)
(defcvar 'SDL_BLENDOPERATION_REV_SUBTRACT 0x3)
(defcvar 'SDL_BLENDOPERATION_MINIMUM 0x4)
(defcvar 'SDL_BLENDOPERATION_MAXIMUM 0x5)

(defcvar 'SDL_BLENDFACTOR_ZERO 0x1)
(defcvar 'SDL_BLENDFACTOR_ONE 0x2)
(defcvar 'SDL_BLENDFACTOR_SRC_COLOR 0x3)
(defcvar 'SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR 0x4)
(defcvar 'SDL_BLENDFACTOR_SRC_ALPHA 0x5)
(defcvar 'SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA 0x6)
(defcvar 'SDL_BLENDFACTOR_DST_COLOR 0x7)
(defcvar 'SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR 0x8)
(defcvar 'SDL_BLENDFACTOR_DST_ALPHA 0x9)
(defcvar 'SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA 0xA)

(defcvar 'SDL_TEXTUREACCESS_STATIC 0x0)
(defcvar 'SDL_TEXTUREACCESS_STREAMING 0x1)
(defcvar 'SDL_TEXTUREACCESS_TARGET 0x2)

(defcvar 'SDL_PIXELFORMAT_RGB888 0x16161804)
(defcvar 'SDL_PIXELFORMAT_RGBA8888 0x16462004)
(defcvar 'SDL_PIXELFORMAT_ARGB8888 0x16362004)

(def-struct 'sdl_rect)
	(int 'x 'y 'w 'h)
(def-struct-end)

(def-struct 'sdl_surface)
	(int 'flags)
	(long 'format)
	(int 'w 'h 'pitch)
	(long 'pixels 'userdata)
	(int 'locked)
	(long 'lockdata)
	(struct 'clip 'sdl_rect)
	(long 'map)
	(int 'obj)
(def-struct-end)

(defcvar 'SDL_RELEASED 0)
(defcvar 'SDL_PRESSED 1)

(defcvar 'SDL_QUIT 0x100)
(defcvar 'SDL_WINDOWEVENT 0x200)
(defcvar 'SDL_KEYDOWN 0x300)
(defcvar 'SDL_KEYUP 0x301)
(defcvar 'SDL_MOUSEMOTION 0x400)
(defcvar 'SDL_MOUSEBUTTONDOWN 0x401)
(defcvar 'SDL_MOUSEBUTTONUP 0x402)
(defcvar 'SDL_MOUSEWHEEL 0x403)

(defcvar 'SDL_WINDOWEVENT_SHOWN 0x1)
(defcvar 'SDL_WINDOWEVENT_HIDDEN 0x2)
(defcvar 'SDL_WINDOWEVENT_EXPOSED 0x3)
(defcvar 'SDL_WINDOWEVENT_MOVED 0x4)
(defcvar 'SDL_WINDOWEVENT_RESIZED 0x5)
(defcvar 'SDL_WINDOWEVENT_SIZE_CHANGED 0x6)
(defcvar 'SDL_WINDOWEVENT_MINIMIZED 0x7)
(defcvar 'SDL_WINDOWEVENT_MAXIMIZED 0x8)
(defcvar 'SDL_WINDOWEVENT_RESTORED 0x9)
(defcvar 'SDL_WINDOWEVENT_ENTER 0xa)
(defcvar 'SDL_WINDOWEVENT_LEAVE 0xb)
(defcvar 'SDL_WINDOWEVENT_FOCUS_GAINED 0xc)
(defcvar 'SDL_WINDOWEVENT_FOCUS_LOST 0xd)
(defcvar 'SDL_WINDOWEVENT_CLOSE 0xe)
(defcvar 'SDL_WINDOWEVENT_TAKE_FOCUS 0xf)
(defcvar 'SDL_WINDOWEVENT_HIT_TEST 0x10)

(def-struct 'sdl_common_event)
	;SDL_KEYDOWN, SDL_KEYUP etc
	(uint 'type 'timestamp)
(def-struct-end)

(def-struct 'sdl_keysym)
	(int 'scancode 'sym)
	(ushort 'mod)
	(uint 'unused)
(def-struct-end)

(def-struct 'sdl_keyboard_event)
	(uint 'type 'timestamp 'windowid)
	(ubyte 'state 'repeat 'padding2 'padding3)
	(struct 'keysym 'sdl_keysym)
(def-struct-end)

(def-struct 'sdl_mouse_motion_event)
	(uint 'type 'timestamp 'windowid 'which 'state)
	(int 'x 'y 'xrel 'yrel)
(def-struct-end)

(def-struct 'sdl_mouse_button_event)
	(uint 'type 'timestamp 'windowid 'which)
	(ubyte 'button 'state 'clicks 'padding1)
	(int 'x 'y)
(def-struct-end)

(def-struct 'sdl_mouse_wheel_event)
	(uint 'type 'timestamp 'windowid 'which)
	(int 'x 'y)
	(uint 'direction)
(def-struct-end)

(def-struct 'sdl_quit_event)
	(uint 'type 'timestamp)
(def-struct-end)

(def-struct 'sdl_window_event)
	(uint 'type 'timestamp 'windowid)
	(ubyte 'event 'padding1 'padding2 'padding3)
	(int 'data1 'data2)
(def-struct-end)

(def-class 'sys_pii)
(dec-method 'exit 'sys/pii/exit 'static '(r0))
(dec-method 'mmap 'sys/pii/mmap 'static '(r0 r1 r2) '(r0))
(dec-method 'munmap 'sys/pii/munmap 'static '(r0 r1 r2) '(r0))
(dec-method 'mprotect 'sys/pii/mprotect 'static '(r0 r1 r2) '(r0))
(dec-method 'open 'sys/pii/open 'static '(r0 r1) '(r0))
(dec-method 'close 'sys/pii/close 'static '(r0) '(r0))
(dec-method 'open_shared 'sys/pii/open_shared 'static '(r0 r1) '(r0))
(dec-method 'close_shared 'sys/pii/close_shared 'static '(r0 r1) '(r0))
(dec-method 'unlink 'sys/pii/unlink 'static '(r0) '(r0))
(dec-method 'stat 'sys/pii/stat 'static '(r0 r1) '(r0))
(dec-method 'write 'sys/pii/write 'static '(r0 r1 r2) '(r0))
(dec-method 'write_char 'sys/pii/write_char 'static '(r0 r1) '(r0))
(dec-method 'write_str 'sys/pii/write_str 'static '(r0 r1) '(r0))
(dec-method 'write_num 'sys/pii/write_num 'static '(r0 r1 r2))
(dec-method 'read 'sys/pii/read 'static '(r0 r1 r2) '(r0))
(dec-method 'read_char 'sys/pii/read_char 'static '(r0) '(r0))
(dec-method 'time 'sys/pii/time 'static nil '(r0))
(dec-method 'clear_icache 'sys/pii/clear_icache 'static '(r0 r1) '(r0))

(dec-method 'lisp_readchar 'sys/pii/lisp_readchar 'static '(r0 r1) '(r0 r1))
(dec-method 'lisp_writechar 'sys/pii/lisp_writechar 'static '(r0 r1) '(r0 r1))
(dec-method 'lisp_time 'sys/pii/lisp_time 'static '(r0 r1) '(r0 r1))
(dec-method 'lisp_age 'sys/pii/lisp_age 'static '(r0 r1) '(r0 r1))

;debug helpers
(defcfun debug-num (s n)
	(when (> *debug_mode* 0)
		(ptr '_a '_b '_c)
		(push-scope)
		(assign '(r0 r1 r2) {_a, _b, _c})
		(assign n '(r0))
		(fn-string (cat s ": ") r1)
		(call 'sys_pii 'write_str '(2 r1))
		(assign {_a, _b} '(r0 r1))
		(call 'sys_pii 'write_num (list 2 r0 16))
		(call 'sys_pii 'write_char (list 2 10))
		(assign {_a, _b, _c} '(r0 r1 r2))
		(pop-scope)))

(defcfun debug-str (s)
	(when (> *debug_mode* 0)
		(ptr '_a '_b)
		(push-scope)
		(assign '(r0 r1) {_a, _b})
		(assign s '(r1))
		(call 'sys_pii 'write_str '(2 r1))
		(call 'sys_pii 'write_char (list 2 10))
		(assign {_a, _b} '(r0 r1))
		(pop-scope)))

(defcfun debug-reg ()
	(when (> *debug_mode* 0)
		(vp-push r14)
		(call 'sys_kernel 'debug_reg (list (cat *stream-name* ":" (str *stream-line*))))
		(vp-pop r14)))
